using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using GameFrameWork;

[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public class UIReuseList : UIBehaviour, IUIReuseList, IUserDataGettable
{
    [SerializeField] RectTransform viewport;
    [SerializeField] RectTransform content;
    [SerializeField] UIReuseItem item;

    bool init;
    ResModule resModule;
    UIReuseItemPool itemPool;
    List<UIReuseContainer> containers;
    int dataCount;
    bool layoutDirty;
    UIReuseViewportDetection viewportDetection;
    UIReuseItem templateItem;
    UIVirtualLayoutGroup layoutGroup;
    IterateSafeList<IUpdate> updates;
    object userData;
    UIReuseList root;
    List<UIReuseList> nestReuseLists;
    bool dynamicSize;
    bool visible => gameObject.activeInHierarchy;
    UIReuseItemKey key;
    UIReuseItemKey Key
    {
        get
        {
            if (key == null)
            {
                var flag = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static;
                var fieldInfo = typeof(UIReuseItemKeys).GetField(item.name, flag);

                Assert.IsNotNull(fieldInfo, $"UIReuseItemKeys can not found field, field name: {item.name}");
                key = fieldInfo.GetValue(null) as UIReuseItemKey;
            }
            return key;
        }
    }

    int lastSelectIndex = -1;
    ReuseItemSelected onSelected = new();
    public ReuseItemSelected OnSelected => onSelected;
    public RectTransform Viewport => viewport;
    public RectTransform Content => content;

    public Vector2 ContentSize
    {
        get
        {
            if (!content) return Vector2.zero;
            return content.sizeDelta;
        }
    }

    public Vector2 GetAnchoredPosition(int index)
    {
        if (containers == null || containers.Count == 0 || containers.Count <= index)
            return Vector2.zero;

        return containers[index].GetAnchoredPosition();
    }

    public Vector3 GetPosition(int index)
    {
        if (containers == null || containers.Count == 0 || containers.Count <= index)
            return Vector2.zero;

        var container = containers[index];
        if (!InViewport(container))
        {
            Debug.LogWarning($"Index不在视口内, 复用列表获取不到世界坐标");
            return Vector2.zero;
        }

        return container.GetPosition();
    }

    public Vector2 GetLocalPosition(int index)
    {
        if (containers == null || containers.Count == 0 || containers.Count <= index)
            return Vector2.zero;

        var container = containers[index];
        if (!InViewport(container))
        {
            Debug.LogWarning($"Index不在视口内, 复用列表获取不到屏幕坐标");
            return Vector2.zero;
        }
        return container.GetLocalPosition();
    }

    object IUserDataGettable.userData => userData;

    bool Invalid => !(item && content);

    protected override void Awake()
    {
        base.Awake();
#if UNITY_EDITOR
        if (!Application.isPlaying)
            return;
#endif
        InternalInitialize();
    }

    protected override void OnEnable()
    {
        base.OnEnable();
#if UNITY_EDITOR
        if (!Application.isPlaying)
            return;
#endif
        if (Invalid) return;

        RefreshAll();
    }

    protected override void OnDisable()
    {
        base.OnDisable();
#if UNITY_EDITOR
        if (!Application.isPlaying)
            return;
#endif
        if (Invalid) return;

        DisableAllContainers();
    }


    protected override void OnDestroy()
    {
        base.OnDestroy();
#if UNITY_EDITOR
        if (!Application.isPlaying)
            return;
#endif
        if (Invalid) return;

        Clear();
    }

    void Update()
    {
        if (updates != null)
        {
            foreach (var update in updates)
                update.Update(Time.deltaTime);
        }
    }

    void LateUpdate()
    {
#if UNITY_EDITOR
        if (!Application.isPlaying)
            return;
#endif
        if (Invalid) return;

        if (viewportDetection.TryUpdate())
        {
            // Must be called in LateUpdate to ensure that the layout is updated before the viewport is updated.
            UpdateViewport(OnItemInViewport, OnItemOutViewport, true);
        }

        if (layoutDirty && !CanvasUpdateRegistry.IsRebuildingLayout())
        {
            layoutDirty = false;
            layoutGroup.Layout();
        }
    }

    void InternalInitialize()
    {
        if (init) return;
        if (Invalid) return;
        layoutGroup = content.GetComponent<UIVirtualLayoutGroup>();
        Assert.IsTrue(layoutGroup, "UIReuseList里Content必须挂上UIVirtualLayoutGroup组件");

        init = true;
        resModule = new ResModule();
        containers = new List<UIReuseContainer>();
        updates = new IterateSafeList<IUpdate>();
        viewportDetection = new UIReuseViewportDetection(viewport, content);
        viewportDetection.TryUpdate();

        if (itemPool == null)
        {
            var pool = new UIReuseItemPool();
            SetItemPool(this, pool);
        }

        templateItem = itemPool.New(item, content);
        templateItem.transform.localPosition = Vector2.zero;
        templateItem.gameObject.SetActive(false);

        dynamicSize = item.TryGetComponent<ContentSizeFitter>(out var _);
    }

    public void Refresh(int count, object userdata = null, int selectIndex = -1)
    {
        if (!visible) return;
        if (Invalid)
        {
            Debug.LogError($"预制上Item或者Content没挂");
            return;
        }
        Assert.IsTrue(dataCount >= 0, "Count必须大于或等于0！！");
        Assert.IsTrue(selectIndex < count, "selectIndex必须小于count！！");

        dataCount = count;
        userData = userdata;
        lastSelectIndex = selectIndex;

        Flush();
        RefreshAll();
    }

    public void RefreshAll()
    {
        if (!visible) return;
        if (Invalid) return;
        if (containers == null) return;

        viewportDetection.TryUpdate();

        UpdateViewport(OnItemInViewport, OnItemOutViewport, false);
    }


    public int Count
    {
        get => dataCount;
    }

    void ForceLayout()
    {
        if (CanvasUpdateRegistry.IsRebuildingLayout())
            layoutDirty = true;
        else
            layoutGroup.Layout();
    }

    void Flush()
    {
        if (dataCount == 0)
        {
            Clean();
            return;
        }

        InternalInitialize();
        ResizeContainers();
        LayoutContainers();
    }


    void ResizeContainers()
    {
        containers ??= new List<UIReuseContainer>();
        int count = containers.Count;
        if (count > dataCount)
        {
            int i = dataCount;
            while (i++ < count)
            {
                int lastIndex = containers.Count - 1;
                var container = containers[lastIndex];
                if (container.IsOccupied)
                {
                    var view = container.View;

                    container.Disable();
                    container.View.SetActive(false);
                    container.View = null;
                    itemPool.Recycle(view);
                }

                containers.RemoveAt(lastIndex);
                layoutGroup.RemoveLayoutElement(container);
                if (container.Ctrl is IUpdate update) updates.Remove(update);
            }
        }
        else
        {
            int i = count;

            while (i < dataCount)
            {
                // 从对象池获取或创建 Item View
                var view = itemPool.New(templateItem, content);
                
                // 通过工厂方法创建控制器并挂载到 View 的 GameObject 上
                var ctrl = Key.CtrlFactory.Invoke(view);

                var container = new UIReuseContainer(i, this, ctrl, resModule, content, viewport);
                container.View = view; // 设置 View

                containers.Add(container);

                layoutGroup.AddLayoutElement(container);

                i++;
            }
        }
    }

    void LayoutContainers()
    {
        templateItem.SetActive(true);
        for (int i = 0; i < dataCount; i++)
        {
            var container = containers[i];

            var view = container.View;

            var template = view != null ? view : templateItem;

            UpdateDynamicSize(container, template, dynamicSize);

            container.View = view;
        }
        templateItem.SetActive(false);
        templateItem.name = item.name;
        layoutGroup.Layout();
    }

    void UpdateDynamicSize(UIReuseContainer container, UIReuseItem view, bool dynamicSize)
    {
        if (dynamicSize)
        {
            container.View = view;
            container.Enable();
            container.Refresh();
            container.View.Layout(true);
            container.CalculateTransformation(view.RectTransform);
            container.Disable();
            container.View = null;
        }
        else
        {
            container.CalculateTransformation(view.RectTransform);
        }
    }


    void DisableAllContainers()
    {
        for (int i = containers.Count - 1; i >= 0; i--)
        {
            var container = containers[i];

            DisableSingleContainer(container);
        }
    }

    void UpdateViewport(Action<UIReuseContainer, bool> enableAction,
            Action<UIReuseContainer, bool> disableAction, bool callInUpdate)
    {
        var viewportbounds = viewportDetection.GetVirtualBounds();
        var worldToViewportMatrix = viewport.worldToLocalMatrix;
        var count = containers.Count;
        for (int i = 0; i < count; i++)
        {
            UIReuseContainer container = containers[i];
            container.UpdateBounds();
            if (viewportbounds.Intersects(container.Bound))
            {
                enableAction?.Invoke(container, callInUpdate);
            }
            else
            {
                disableAction?.Invoke(container, callInUpdate);
            }
        }
    }

    bool InViewport(UIReuseContainer container)
    {
        var viewportbounds = viewportDetection.GetVirtualBounds();
        container.UpdateBounds();
        return viewportbounds.Intersects(container.Bound);
    }

    void OnItemInViewport(UIReuseContainer container, bool callInUpdate)
    {
        if (container.IsOccupied)
        {
            if (!callInUpdate)
                container.Refresh();
        }
        else
        {
            EnableSingleContainer(container);
            container.Refresh();
        }

        if (dynamicSize) container.View.Layout(true);

        container.Apply();
    }

    void OnItemOutViewport(UIReuseContainer container, bool callInUpdate)
    {
        if (!container.IsOccupied)
            return;

        DisableSingleContainer(container);
    }

    void DeleteContainers()
    {
        if (containers == null || containers.Count == 0) return;
        
        for (int i = containers.Count - 1; i >= 0; i--)
        {
            var container = containers[i];

            DisableSingleContainer(container);

            layoutGroup.RemoveLayoutElement(container);
        }
        containers.Clear();
        layoutGroup.Layout();
    }

    void EnableSingleContainer(UIReuseContainer container)
    {
        if (container != null && !container.IsOccupied)
        {
            var view = itemPool.New(item, content);
            container.View = view;
            container.View.SetActive(true);
            container.Enable();
            if (container.Ctrl is IUpdate update) updates.Add(update);
        }
    }

    void DisableSingleContainer(UIReuseContainer container)
    {
        if (container != null && container.IsOccupied)
        {
            var view = container.View;
            container.Disable();
            container.View.SetActive(false);
            container.View = null;
            if (container.Ctrl is IUpdate update) updates.Remove(update);
            itemPool.Recycle(view);
        }
    }


    void Clean()
    {
        lastSelectIndex = -1;
        dataCount = 0;
        layoutDirty = false;
        updates?.Clear();
        DeleteContainers();
    }

    void Clear()
    {
        Clean();
        itemPool?.ReleaseAll();
        resModule.Dispose();
    }

    void SetItemPool(UIReuseList reuselist, UIReuseItemPool pool, bool recursion = true)
    {
        if (recursion && reuselist.item)
        {
            var nestReuselists = reuselist.item.GetNestReuseList();
            foreach (var nest in nestReuselists)
                SetItemPool(nest, pool);
        }
        reuselist.itemPool = pool;
    }


    /// <summary>
    /// Invoke by internal, don't call it.
    /// </summary>
    /// <param name="index"></param>
    public void OnItemClick(int index)
    {
        Select(index);
    }

    public void Select(int index)
    {
        if (lastSelectIndex == index) return;

        try
        {
            // 移除了 GameEntry.Sound.PlayUISound(Constant.Music.Click);
            // 如果需要音效，可以在这里添加自定义的音效播放逻辑
            // 例如：AudioManager.Instance.PlaySound("Click");

            onSelected?.Invoke(lastSelectIndex, index);
        }
        catch (Exception e)
        {
            Debug.LogException(e);
        }
        finally
        {
            lastSelectIndex = index;
        }

        RefreshAll();
    }

    public bool IsSelected(int index)
    {
        return lastSelectIndex == index;
    }
}

